import express from "express"
import { createServer } from "http"
import { Server } from "socket.io"
import cors from "cors"
import { GameManager } from "./gameManager.js"
import { WordBankManager } from "./wordBankManager.js"

const app = express()
const server = createServer(app)

const allowlist = [
  "http://draw-guess.bdow.com.cn",
  "https://draw-guess.bdow.com.cn",
];

const io = new Server(server, {
  cors: {
    origin: allowlist,
    methods: ["GET", "POST"],
    credentials: true,
  },
  transports: ["websocket", "polling"],
})

// 中间件
app.use(
  cors({
    origin(origin, cb) {
      // 允许无 Origin 的情况（如 curl/健康检查）
      if (!origin) return cb(null, true);
      cb(null, allowlist.includes(origin));
    },
    credentials: true,
  })
);
app.use(express.json())

// 信任反向代理的 X-Forwarded-For / Proto
app.set("trust proxy", 1);

// 游戏管理器和题库管理器
const gameManager = new GameManager()
const wordBankManager = new WordBankManager()

// 服务器侧的房间计时器与下一轮触发器
const roomTimers = new Map() // roomId -> setInterval handle
const nextRoundTimeouts = new Map() // roomId -> setTimeout handle

function clearServerTimer(roomId) {
  const h = roomTimers.get(roomId)
  if (h) {
    clearInterval(h)
    roomTimers.delete(roomId)
  }
  // 同步清空到 GameManager（若其内部也存引用）
  gameManager.setRoomTimer(roomId, null)
}

function clearNextRoundTimeout(roomId) {
  const t = nextRoundTimeouts.get(roomId)
  if (t) {
    clearTimeout(t)
    nextRoundTimeouts.delete(roomId)
  }
}

function scheduleNextRound(roomId, delayMs = 3000) {
  // 防重复调度
  if (nextRoundTimeouts.has(roomId)) return
  const t = setTimeout(() => {
    nextRoundTimeouts.delete(roomId)
    startNextRound(roomId)
  }, delayMs)
  nextRoundTimeouts.set(roomId, t)
}

// 基础路由
app.get("/", (req, res) => {
  res.json({
    message: "你画我猜游戏服务器运行中",
    version: "1.0.0",
    activeRooms: gameManager.getActiveRoomsCount(),
    totalPlayers: gameManager.getTotalPlayersCount(),
  })
})

// 健康监测
app.get("/api/health", (req, res) => {
  res.json({ ok: true, version: "1.0.0" });
});

// 获取题库列表
app.get("/api/wordbanks", (req, res) => {
  res.json(wordBankManager.getAllWordBanks())
})

// 获取特定题库
app.get("/api/wordbanks/:id", (req, res) => {
  const wordBank = wordBankManager.getWordBank(req.params.id)
  if (wordBank) {
    res.json(wordBank)
  } else {
    res.status(404).json({ error: "题库不存在" })
  }
})

// 创建自定义题库
app.post("/api/wordbanks", (req, res) => {
  try {
    const { name, words } = req.body
    if (!name || !Array.isArray(words) || words.length === 0) {
      return res.status(400).json({ error: "题库名称和词汇列表不能为空" })
    }

    const wordBank = wordBankManager.createWordBank(name, words)
    res.status(201).json(wordBank)
  } catch (error) {
    res.status(500).json({ error: "创建题库失败: " + error.message })
  }
})

// Socket.IO 连接处理
io.on("connection", (socket) => {
  console.log(`玩家连接: ${socket.id}`)

  // 加入房间
  socket.on("join-room", async (data) => {
    try {
      const { roomId, playerName } = data
      console.log(`玩家 ${playerName} (${socket.id}) 尝试加入房间 ${roomId}`)

      const result = await gameManager.joinRoom(roomId, socket.id, playerName, socket)

      if (result.success) {
        socket.join(roomId)
        socket.emit("room-joined", {
          success: true,
          playerId: socket.id,
          gameState: result.gameState,
        })

        // 通知房间内其他玩家
        socket.to(roomId).emit("player-joined", {
          player: result.player,
          players: result.gameState.players,
        })

        console.log(`玩家 ${playerName} 成功加入房间 ${roomId}`)
      } else {
        socket.emit("room-joined", { success: false, error: result.error })
      }
    } catch (error) {
      console.error("加入房间错误:", error)
      socket.emit("error", { message: "加入房间失败" })
    }
  })

  // 离开房间
  socket.on("leave-room", (data) => {
    const { roomId } = data
    handlePlayerLeave(socket, roomId)
  })

  // 绘画数据同步
  socket.on("draw-stroke", (data) => {
    const { roomId, stroke } = data
    console.log(`收到绘画数据: 房间 ${roomId}, 笔画 ${stroke.id}`)

    // 验证玩家是否是当前绘画者
    if (gameManager.isCurrentDrawer(roomId, socket.id)) {
      // 广播给房间内其他玩家
      socket.to(roomId).emit("stroke-received", { stroke })

      // 保存笔画到游戏状态
      gameManager.addStroke(roomId, stroke)
    }
  })

  // 清除画布
  socket.on("clear-canvas", (data) => {
    const { roomId } = data
    console.log(`清除画布: 房间 ${roomId}`)

    if (gameManager.isCurrentDrawer(roomId, socket.id)) {
      io.to(roomId).emit("canvas-cleared")
      gameManager.clearStrokes(roomId)
    }
  })

  // 撤回最后一笔
  socket.on("undoStroke", (data) => {
    const { roomId } = data
    console.log(`撤回最后一笔: 房间 ${roomId}`)

    if (gameManager.isCurrentDrawer(roomId, socket.id)) {
      socket.to(roomId).emit("stroke-undone")
      gameManager.removeLastStroke(roomId)
    }
  })

  // 猜词
  socket.on("guess-word", async (data) => {
    const { roomId, guess, playerId } = data
    console.log(`收到猜测: 房间 ${roomId}, 玩家 ${playerId}, 猜测 "${guess}"`)

    try {
      const result = await gameManager.processGuess(roomId, playerId, guess)

      // 广播猜测结果
      io.to(roomId).emit("guess-received", {
        playerId: result.playerId,
        playerName: result.playerName,
        guess: result.guess,
        isCorrect: result.isCorrect,
      })

      if (result.isCorrect) {
        // 第一时间更新状态
        const gameState = gameManager.getGameState(roomId)
        io.to(roomId).emit("game-state-updated", { gameState })

        // 清除当前轮计时器，防止重入
        clearServerTimer(roomId)
        clearNextRoundTimeout(roomId)

        // 3秒后进入下一轮（带防抖）
        scheduleNextRound(roomId, 3000)
      }
    } catch (error) {
      console.error("处理猜测错误:", error)
      socket.emit("error", { message: "处理猜测失败" })
    }
  })

  // 开始游戏
  socket.on("start-game", async (data) => {
    const { roomId, config } = data
    console.log(`开始游戏: 房间 ${roomId}`, config)

    try {
      const result = await gameManager.startGame(roomId, wordBankManager, config)

      if (result.success) {
        io.to(roomId).emit("game-started", { gameState: result.gameState })
        // 先清旧计时器再开新计时
        clearServerTimer(roomId)
        startRoundTimer(roomId)
      } else {
        socket.emit("error", { message: result.error })
      }
    } catch (error) {
      console.error("开始游戏错误:", error)
      socket.emit("error", { message: "开始游戏失败" })
    }
  })

  // 重新开始游戏
  socket.on("restart-game", (data) => {
    const { roomId } = data
    console.log(`重新开始游戏: 房间 ${roomId}`)

    try {
      // 清理所有与轮次相关的计时器
      clearServerTimer(roomId)
      clearNextRoundTimeout(roomId)

      const result = gameManager.restartGame(roomId)
      if (result.success) {
        io.to(roomId).emit("game-restarted", { gameState: result.gameState })
      }
    } catch (error) {
      console.error("重新开始游戏错误:", error)
      socket.emit("error", { message: "重新开始游戏失败" })
    }
  })

  // 断开连接处理
  socket.on("disconnect", () => {
    console.log(`玩家断开连接: ${socket.id}`)
    handlePlayerDisconnect(socket)
  })
})

// 处理玩家离开房间
function handlePlayerLeave(socket, roomId) {
  if (roomId) {
    const result = gameManager.leaveRoom(roomId, socket.id)
    if (result.success) {
      socket.leave(roomId)

      // 如果房间没人了，清理计时器/定时器
      if (!result.players || result.players.length === 0) {
        clearServerTimer(roomId)
        clearNextRoundTimeout(roomId)
      }

      // 通知房间内其他玩家
      socket.to(roomId).emit("player-left", {
        playerId: socket.id,
        players: result.players,
      })

      console.log(`玩家 ${socket.id} 离开房间 ${roomId}`)
    }
  }
}

// 处理玩家断开连接
function handlePlayerDisconnect(socket) {
  const roomId = gameManager.getPlayerRoom(socket.id)
  if (roomId) {
    handlePlayerLeave(socket, roomId)
  }
}

// 开始下一轮（统一在这里清旧计时器 -> 开新计时器）
async function startNextRound(roomId) {
  try {
    // 避免多重启动：先清除可能残留的超时器与计时器
    clearNextRoundTimeout(roomId)
    clearServerTimer(roomId)

    const result = await gameManager.startNextRound(roomId, wordBankManager)

    if (result.success) {
      // 广播最新状态
      io.to(roomId).emit("game-state-updated", { gameState: result.gameState })
      // 开启新一轮倒计时
      startRoundTimer(roomId)
    } else {
      // 游戏结束
      io.to(roomId).emit("game-finished", { finalScores: result.finalScores })
    }
  } catch (error) {
    console.error("开始下一轮错误:", error)
  }
}

// 回合计时器（使用房间配置 roundTime）
function startRoundTimer(roomId) {
  const initialState = gameManager.getGameState(roomId)
  if (!initialState) return

  // 安全起见再次清一遍旧计时器
  clearServerTimer(roomId)

  const roundTime = Number(initialState.roundTime) || 60
  let timeLeft = roundTime

  const handle = setInterval(() => {
    timeLeft = Math.max(0, timeLeft - 1)

    // 更新游戏状态中的时间
    gameManager.updateTimeLeft(roomId, timeLeft)

    // 广播时间更新（带上完整状态，避免前端状态不一致）
    const current = gameManager.getGameState(roomId)
    if (!current) {
      clearServerTimer(roomId)
      return
    }
    io.to(roomId).emit("game-state-updated", { gameState: current })

    if (timeLeft === 30) {
      io.to(roomId).emit("time-warning", { message: "还剩30秒！", timeLeft })
    } else if (timeLeft === 10) {
      io.to(roomId).emit("time-warning", { message: "最后10秒！", timeLeft })
    }

    if (timeLeft <= 0) {
      // 时间到，结束当前轮
      clearServerTimer(roomId)

      io.to(roomId).emit("round-ended", {
        correctWord: current.currentWord,
        scores: gameManager.getScores(roomId),
      })

      // 3秒后开始下一轮（防重复）
      scheduleNextRound(roomId, 3000)
    }
  }, 1000)

  // 保存计时器引用以便清理（双写到本地与 gameManager）
  roomTimers.set(roomId, handle)
  gameManager.setRoomTimer(roomId, handle)
}

const PORT = process.env.PORT || 3001

server.listen(PORT, "127.0.0.1", () => {
  console.log(`🎮 你画我猜游戏服务器启动成功!`)
  console.log(`🌐 服务器地址: http://127.0.0.1:${PORT}`)
  console.log(`🔌 WebSocket 端口: ${PORT}`)
  console.log(`📚 默认题库已加载: ${wordBankManager.getAllWordBanks().length} 个`)
})

// 优雅关闭
process.on("SIGTERM", () => {
  console.log("收到 SIGTERM 信号，正在关闭服务器...")
  server.close(() => {
    console.log("服务器已关闭")
    process.exit(0)
  })
})
